import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.ImageCanvas;
import ij.gui.Toolbar;
import ij.io.FileInfo;
import ij.io.FileSaver;
import ij.io.OpenDialog;
import ij.io.SaveDialog;
import ij.plugin.PlugIn;
import ij.process.ImageProcessor;
import ij.process.StackConverter;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;


/**
*
* Bachelor thesis at the Institute of Biomedical Engineering, 
* located at the UMIT/EWZ campus in Hall in Tyrol. <br><br>
*
* This is the main class for the plugin. Everything is initialized an controlled from here
* 
* @author Stefan Fuchs
*
*/
public class HeartCellGenerator_ implements PlugIn, MouseMotionListener, MouseListener,
		SelectionListener, ModifyListener, VerifyListener {

	//////////////// INITIAL PARAMETERS //////////////////////
	
	private static final int MIN_COLOR_ONE = 2;
	
	private static final int MAX_COLOR_ONE = 10;
	
	private static final int AVG_COLOR_ONE = 4;
	
	private static final int MIN_COLOR_TWO = 2;
	
	private static final int MAX_COLOR_TWO = 10;
	
	private static final int AVG_COLOR_TWO = 4;
	
	private static final String PATH = "/home/fixl/Umit/bak/Daten/Datensatz/results/rollingBall.tiff";
	
//	private static final String PATH = "/home/fixl/Umit/bak/Daten/Datensatz/results/rollingBall_copy.tif";
	
	private static final boolean useDialogs = false;
	
	
	//////////////////////////////////////////////////
	
	// finales

	/** The available Neighorhoods */
	private static final String[] NEIGHBORHOOD_COMBO_LABELS = {
			"Moore Neighborhood", "von Neumann Neighborhood" };

	/** The available max. Greyvalue options */
	private static final String[] MAX_GREYVALUE_LABELS = { "Global", "Local" };

	/** The available Distances */
	private static final String[] DISTANCE_LABELS = { "Euclidean Distance",
			"Manhatten Distance" };

	// ImageJ Objects
	/** The current Image */
	private ImagePlus currentImage;
	
	/** The ASF Image */
	private ImagePlus asfImage;
	
	/** The Rolling Ball Image*/
	private ImagePlus rollingBallImage;

	/** The Image's Canvas */
	private ImageCanvas canvas;

	// int
	/** 1D-Volume of the Image */
	private int[] volume;

	/** Pencil Size */
	private int pencilSize = 4;

	/** Height of the Image */
	private int height;

	/** Width of the Image */
	private int width;

	/** Amount of Slices in the stack */
	private int size;

	/** Min Roi-Prameters X-Axis */
	private int minRoiX;

	/** Max Roi-Prameters X-Axis */
	private int maxRoiX;

	/** Min Roi-Prameters Y-Axis */
	private int minRoiY;

	/** Max Roi-Prameters Y-Axis */
	private int maxRoiY;

	/** Min Roi-Prameters Z-Axis */
	private int minRoiZ;

	/** Max Roi-Prameters Z-Axis */
	private int maxRoiZ;

	/** Counter for creating Filenmmes */
	private int seqCounter;

	// booleans

	/** Indicator if ROI is already marked. */
	private boolean roiMarked;

	/** Indicator if border is already marked. */
	private boolean borderMarked;

	/** Indicator which Button is toggled */
	private boolean markRoi = false;

	/** Indicator which button is toggled */
	private boolean markBorder = false;
	
	/** Indicator if ASF has allready taken place */
	private boolean afterASF = false;
	
	/** Indicator if Rolling Ball has allready taken place*/
	private boolean afterRollingBall = false;
	
	/** Indicator if we are after the rolling ball correction*/
	private boolean afterRollingBallCorrection = false;
	
	/** Indicator if "manually add Voxels" is for ASF selected */
	private boolean manuallyAddASFVoxels = false;
	
	/** Indicator if "manually delete Voxels" is for ASF selected */
	private boolean manuallyDeleteASFVoxels = false;
	
	/** Indicator if "manually add Voxels" is for Rolling Ball selected */
	private boolean manuallyAddRollingBallVoxels = false;
	
	/** Indicator if "manually delete Voxels" is for Rolling Ball selected */
	private boolean manuallyDeleteRollingBallVoxels = false;
	
	/** Indicator wether the AV-Node should be drawn*/
	private boolean drawAVNode = false;
	
	/** Indicator if the Image was loaded from Overlay*/
	private boolean loadedFromOverlay = false;
	
	// Misc

	/** {@link ArrayList} of the external Border {@link Voxel}s */
	private ArrayList<Voxel> internalVoxels = null;

	/** {@link ArrayList} of internal {@link Voxel}s */
	private ArrayList<Voxel> externalVoxels = null;
	
	/** Arraylist of manually added ASF Voxels */
	private ArrayList<Voxel> manuallyAddedASFVoxels = null;
	
	/** Arraylist of manually deleted ASF Voxels */
	private ArrayList<Voxel> manuallyDeletedASFVoxels = null;;
	
	/** Arraylist of manually added rolling Ball Voxels */
	private ArrayList<Voxel> manuallyAddedRollingBallVoxels = null;
	
	/** Arraylist of manually deleted Rolling Ball Voxels */
	private ArrayList<Voxel> manuallyDeletedRollingBallVoxels = null;
	
	/** Arraylist containing the AV-Node voxels*/
	private ArrayList<Voxel> avNodeVoxels = null;
	
	/** The Modell instance */
	private Modell modell = null;

	/** Cellular Automaton for Segemntation */
	private CASegmentation3D ca3Dseg = null;
	
	/** Alternating Sequential Filter for morphological Operations*/
	private AlternatingSequentialFilter morphFilter = null;
	
	/** Manual Correction Filter*/
	private ManualCorrectionLabeling manualLabelingFilter = null;
	
	/** Manual Correction for Rolling Ball Results*/
	private ManualRollingBallCorrection manualCorrectRollingBall = null;
	
	/** Rolling Ball Operation*/
	private RollingBallOperator rollingBall = null;
	
	/** Creator of the nervous system*/
	private ConductorSystemCreator conductorSystemCreator = null;

	/** The GUI Components */
	private GUIPluginMain gui;
	
	/** The Display*/
	private Display display;
	
	/** The Shell*/
	private Shell shell;
	// //////////////////////////////////////////////////////////

	@Override
	public void run(String arg) {

		// Initialize necessary datastructures
		this.internalVoxels = new ArrayList<Voxel>();
		this.externalVoxels = new ArrayList<Voxel>();
		this.manuallyAddedASFVoxels = new ArrayList<Voxel>();
		this.manuallyDeletedASFVoxels = new ArrayList<Voxel>();
		this.manuallyAddedRollingBallVoxels = new ArrayList<Voxel>();
		this.manuallyDeletedRollingBallVoxels = new ArrayList<Voxel>();
		this.avNodeVoxels = new ArrayList<Voxel>();
		this.ca3Dseg = CASegmentation3D.getInstance();
		this.modell = Modell.getInstance();
		this.gui = new GUIPluginMain();

		this.display = new Display();
		this.shell = new Shell(display);

		// Just a precaution
		if (ij.WindowManager.getWindowCount() < 1) {
			IJ.showMessage("Error", "No Image opened!");
			this.shell.dispose();
			this.display.dispose();
			return;
		} else {
			currentImage = ij.WindowManager.getCurrentImage();
			int type = currentImage.getType();
			if (type != ImagePlus.GRAY16
					|| currentImage.getStack().getSize() <= 1) {
				IJ.showMessage("Error",
						"Only 16-Bit Grayvalue Stacks are supported!");
				return;
			}

		}
		
		// Initializes & Configure the GUI-Elements
		gui.initGUI(shell);
		configureGUI();

		// Prepear the imge Sequence for further operations
		prepearSequence();

		shell.pack();
		shell.open();
		// GUI-Loop
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		display.dispose();
	}

	/**
	 * Method to configure the GUI Elements
	 * 
	 * @param shell
	 *            The Shell
	 */
	private void configureGUI() {
		
		///////////////////////////////
		///////Segmentation Group /////
		///////////////////////////////
		
		// The Textfield containing the name of the opened Image
		this.gui.openedImageText.setText(currentImage.getTitle());

		// markBorder Button listener
		this.gui.markBorderButton.addSelectionListener(this);

		// markRoi Button listener
		this.gui.markROIButton.addSelectionListener(this);

		// Pencil Size Spinner
		this.gui.pencilSizeSpinner.setMinimum(2);
		this.gui.pencilSizeSpinner.setMaximum(16);
		this.gui.pencilSizeSpinner.setIncrement(1);
		this.gui.pencilSizeSpinner.setDigits(0);
		this.gui.pencilSizeSpinner.setSelection(pencilSize);
		this.gui.pencilSizeSpinner.addModifyListener(this);

		// Neighborhood Combo boxes
		this.gui.neighborhoodCombo.setItems(NEIGHBORHOOD_COMBO_LABELS);
		this.gui.neighborhoodCombo.select(0);

		// max Greyvalue Combo boxes
		this.gui.maxGreyValueCombo.setItems(MAX_GREYVALUE_LABELS);
		this.gui.maxGreyValueCombo.select(0);

		// Distance Combo boxes
		this.gui.distanceCombo.setItems(DISTANCE_LABELS);
		this.gui.distanceCombo.select(0);


		// Strength between slices
		this.gui.strengthScale.setMinimum(1);
		this.gui.strengthScale.setMaximum(1);
		this.gui.strengthScale.setIncrement(1);
		this.gui.strengthScale.setPageIncrement(1);
		this.gui.strengthScale.setSelection(100);
		this.gui.strengthScale.addSelectionListener(this);

		// From-To-Slices
		this.gui.selectSlicesButton.addSelectionListener(this);

		this.gui.fromSpinner.setEnabled(false);
		this.gui.fromSpinner.setMinimum(1);
		this.gui.fromSpinner.setDigits(0);
		this.gui.fromSpinner.setMaximum(this.currentImage.getStack().getSize());
		this.gui.fromSpinner.setSelection(1);
		this.gui.fromSpinner.addModifyListener(this);

		this.gui.toSpinner.setEnabled(false);
		this.gui.toSpinner.setMinimum(1);
		this.gui.toSpinner.setDigits(0);
		this.gui.toSpinner.setMaximum(this.currentImage.getStack().getSize());
		this.gui.toSpinner.setSelection(this.currentImage.getStack().getSize());
		this.gui.toSpinner.addModifyListener(this);

		// Performance
		this.gui.performanceScale.setMinimum(1);
		this.gui.performanceScale.setMaximum(5);
		this.gui.performanceScale.setIncrement(1);
		this.gui.performanceScale.setPageIncrement(1);
		this.gui.performanceScale.setSelection(2);

		// Reset Button
		this.gui.resetButton.addSelectionListener(this);

		// Segmentation Button
		this.gui.segmentationButton.setEnabled(false);
		this.gui.segmentationButton.addSelectionListener(this);

		// Save Button
		this.gui.saveButton.addSelectionListener(this);
		
		////////////////////////////////////////////////
		//// Alternating Sequence Filter ///////////////
		////////////////////////////////////////////////
		
		//Default selection of the radio button
		this.gui.openCloseButton.setSelection(true);
		
		//StructureElements Spinner
		this.gui.asfSpinner.setMinimum(1);
		this.gui.asfSpinner.setMaximum(10);
		this.gui.asfSpinner.setIncrement(1);
		this.gui.asfSpinner.setDigits(0);
		this.gui.asfSpinner.addModifyListener(this);
		
		//asf-Start-Button
		this.gui.asfStartButton.setEnabled(false);
		this.gui.asfStartButton.addSelectionListener(this);
		
		//Manually correct ASF
		this.gui.manualASFCorrectAddButton.setEnabled(false);
		this.gui.manualASFCorrectAddButton.addSelectionListener(this);
		this.gui.manualASFCorrectDeleteButton.addSelectionListener(this);
		this.gui.manualASFCorrectDeleteButton.setEnabled(false);
		this.gui.manualASFCorrectStartButton.setEnabled(false);
		this.gui.manualASFCorrectStartButton.addSelectionListener(this);
		
		////////////////////////////////////////////////
		//// Rolling Ball //////////////////////////////
		////////////////////////////////////////////////
		//Color of the Labels to indicate the wall thickness of each ventricel
		
		this.gui.minColorOneSpinner.setSelection(MIN_COLOR_ONE);
		this.gui.minColorOneSpinner.setIncrement(1);
		this.gui.minColorOneSpinner.setDigits(0);
		this.gui.minColorOneSpinner.addModifyListener(this);
		
		this.gui.maxColorOneSpinner.setSelection(MAX_COLOR_ONE);
		this.gui.maxColorOneSpinner.setIncrement(1);
		this.gui.maxColorOneSpinner.setDigits(0);
		this.gui.maxColorOneSpinner.addModifyListener(this);
		
		this.gui.avgColorOneSpinner.setMinimum(MIN_COLOR_ONE);
		this.gui.avgColorOneSpinner.setMaximum(MAX_COLOR_ONE);
		this.gui.avgColorOneSpinner.setSelection(AVG_COLOR_ONE);
		this.gui.avgColorOneSpinner.setIncrement(1);
		this.gui.avgColorOneSpinner.setDigits(0);
		this.gui.avgColorOneSpinner.addModifyListener(this);
		
		this.gui.avgColorTwoSpinner.setMinimum(MIN_COLOR_TWO);
		this.gui.avgColorTwoSpinner.setMaximum(MAX_COLOR_TWO);
		this.gui.avgColorTwoSpinner.setSelection(AVG_COLOR_TWO);
		this.gui.avgColorTwoSpinner.setIncrement(1);
		this.gui.avgColorTwoSpinner.setDigits(0);
		this.gui.avgColorTwoSpinner.addModifyListener(this);
		
		this.gui.minColorTwoSpinner.setSelection(MIN_COLOR_TWO);
		this.gui.minColorTwoSpinner.setIncrement(1);
		this.gui.minColorTwoSpinner.setDigits(0);
		this.gui.minColorTwoSpinner.addModifyListener(this);
		
		this.gui.maxColorTwoSpinner.setSelection(MAX_COLOR_TWO);
		this.gui.maxColorTwoSpinner.setIncrement(1);
		this.gui.maxColorTwoSpinner.setDigits(0);
		this.gui.maxColorTwoSpinner.addModifyListener(this);
		
		this.gui.minGrayValueText.addVerifyListener(this);
		this.gui.maxGrayValueText.addVerifyListener(this);
		
		this.gui.rollingBallStartButton.addSelectionListener(this);
		this.gui.rollingBallStartButton.setEnabled(false);
		this.gui.rollingBallSaveButton.addSelectionListener(this);
		this.gui.rollingBallSaveButton.setEnabled(false);
		
		this.gui.rollingBallZSliceSpinner.setMinimum(1);
		 
		this.gui.rollingBallZSliceSpinner.setMaximum(this.gui.maxColorOneSpinner.getSelection() > this.gui.maxColorTwoSpinner.getSelection() ? this.gui.maxColorOneSpinner.getSelection() : this.gui.maxColorTwoSpinner.getSelection());
		this.gui.rollingBallZSliceSpinner.setDigits(0);
		this.gui.rollingBallZSliceSpinner.addModifyListener(this);
		
		//Manual Correction of rolling Ball results
		
		this.gui.manualRollingBallCorrectAddButton.setEnabled(false);
		this.gui.manualRollingBallCorrectAddButton.setSelection(false);
		this.gui.manualRollingBallCorrectAddButton.addSelectionListener(this);
		
		this.gui.manualRollingBallCorrectDeleteButton.setEnabled(false);
		this.gui.manualRollingBallCorrectDeleteButton.setSelection(false);
		this.gui.manualRollingBallCorrectDeleteButton.addSelectionListener(this);
		
		this.gui.manualRollingBallCorrectStartButton.setEnabled(false);
		this.gui.manualRollingBallCorrectStartButton.addSelectionListener(this);
		
		//electrical Group
		this.gui.loadBinaryImageButton.addSelectionListener(this);
		
		this.gui.conductorDrawAVNodeButton.addSelectionListener(this);
		
		this.gui.conductorStartDrawing.addSelectionListener(this);
		this.gui.conductorStartDrawing.setEnabled(false);
	}

	/**
	 * Prepear the Sequence and convert it to RGB to be drawn on
	 */
	private void prepearSequence() {
		int sliceCounter;
		this.seqCounter = 1;
		
		FileInfo fileInfo = this.currentImage.getFileInfo();
		
		this.modell.setVoxelDepth(fileInfo.pixelDepth);
		this.modell.setVoxelHeight(fileInfo.pixelHeight);
		this.modell.setVoxelWidth(fileInfo.pixelWidth);
		
		sliceCounter = this.currentImage.getSlice();
		
		StackConverter con = new StackConverter(this.currentImage);
		
		con.convertToGray8();
		this.modell.setGrayValueImageStack(Util.copyStack(this.currentImage.getStack()));
		
		con.convertToRGB();
		
		// Backup the stack
		this.modell.setImageStack(Util.copyStack(this.currentImage.getStack()));
		
		this.volume = calcVolume(this.currentImage);
		this.currentImage.setSlice(sliceCounter);

	}

	/**
	 * Calculates the 1D-Volume of the Image
	 * 
	 * @param image
	 *            The Image of which we want the volume
	 * @return The Volume in 1D
	 */
	private int[] calcVolume(ImagePlus image) {
		ImageProcessor slice = null;
		int[] volume;

		this.height = image.getStack().getHeight();
		this.width = image.getStack().getWidth();
		this.size = image.getStack().getSize();
		this.modell.setDimension(this.width, this.height, this.size);

		volume = new int[this.height * this.width * this.size];

		for (int z = 1; z <= this.size; z++) {
			slice = image.getStack().getProcessor(z);

			for (int y = 0; y < this.height; y++) {
				for (int x = 0; x < this.width; x++) {
					int[] pixel = new int[3];
					slice.getPixel(x, y, pixel);
					volume[(this.width * (this.height * (z - 1) + y) + x)] = pixel[0];
				}
			}
		}
		return volume;
	}

	/**
	 * Method that draws the Border on the Image
	 * 
	 * @param x
	 *            Offscreen-X
	 * @param y
	 *            Offscreen-Y
	 * @param image
	 *            The Image
	 */
	private void drawBorder(int x, int y, ImagePlus image) {

		if (x > this.width || y > this.height) {
			return;
		}

		ImageProcessor tmpProc = image.getProcessor();

		tmpProc.setColor(Modell.EXTERNAL_POINTS_LABEL);
		tmpProc.setLineWidth(this.pencilSize);
		tmpProc.drawDot(x, y);

		for (int yy = -(int) (this.pencilSize / 2d); yy < (int) (this.pencilSize / 2d); yy++) {
			for (int xx = -(int) (this.pencilSize / 2d); xx < (int) (this.pencilSize / 2d); xx++) {

				if ((x + xx) < 0 || (y + yy) < 0 || (x + xx) > this.width
						|| (y + yy) > this.height) {
					continue;
				}
				this.externalVoxels.add(new Voxel((x + xx), (y + yy), (image
						.getCurrentSlice() - 1), Modell.EXTERNAL_POINTS_LABEL
						.getRGB()));
			}
		}
		image.updateAndDraw();
	}

	/**
	 * Method that draws the Roi on the Image
	 * 
	 * @param x
	 *            Offscreen-X
	 * @param y
	 *            Offscreen-Y
	 * @param image
	 *            The Image
	 */
	private void drawRoi(int x, int y, ImagePlus image) {

		if (x > this.width || y > this.height) {
			return;
		}

		ImageProcessor tmpProc = image.getProcessor();

		tmpProc.setColor(Modell.INTERNAL_POINTS_LABEL);
		tmpProc.setLineWidth(this.pencilSize);
		tmpProc.drawDot(x, y);

		for (int yy = -(int) (this.pencilSize / 2d); yy < (int) (this.pencilSize / 2d); yy++) {
			for (int xx = -(int) (this.pencilSize / 2d); xx < (int) (this.pencilSize / 2d); xx++) {

				if ((x + xx) < 0 || (y + yy) < 0 || (x + xx) > this.width
						|| (y + yy) > this.height) {
					continue;
				}
				this.internalVoxels.add(new Voxel((x + xx), (y + yy), (image
						.getCurrentSlice() - 1), Modell.INTERNAL_POINTS_LABEL
						.getRGB()));
			}
		}
		image.updateAndDraw();
	}
	
	/**
	 * Method that draws added Voxels on the Image
	 * 
	 * @param x
	 *            Offscreen-X
	 * @param y
	 *            Offscreen-Y
	 * @param image
	 *            The Image
	 */
	private void drawAddedASFVoxels(int x, int y, ImagePlus image) {
		if (x > this.width || y > this.height) {
			return;
		}

		ImageProcessor tmpProc = image.getProcessor();

		tmpProc.setColor(Modell.MANUALLY_ADDED_VOXELS);
		tmpProc.setLineWidth(1);
		tmpProc.drawDot(x, y);
		
		this.manuallyAddedASFVoxels.add(new Voxel(x, y, (image.getCurrentSlice() - 1), Modell.MANUALLY_ADDED_VOXELS.getRGB()));
		
		image.updateAndDraw();
	}
	
	/**
	 * Method that draws deleted Voxels on the Image
	 * 
	 * @param x
	 *            Offscreen-X
	 * @param y
	 *            Offscreen-Y
	 * @param image
	 *            The Image
	 */
	private void drawDeletedASFVoxels(int x, int y, ImagePlus image) {

		if (x > this.width || y > this.height) {
			return;
		}

		ImageProcessor tmpProc = image.getProcessor();

		tmpProc.setColor(Modell.MANUALLY_DELETED_VOXELS);
		tmpProc.setLineWidth(1);
		tmpProc.drawDot(x, y);

		this.manuallyDeletedASFVoxels.add(new Voxel(x, y, (image.getCurrentSlice() - 1), Modell.MANUALLY_DELETED_VOXELS.getRGB()));
		
		image.updateAndDraw();
	}
	
	/**
	 * Method that draws added Voxels on the Image
	 * 
	 * @param x
	 *            Offscreen-X
	 * @param y
	 *            Offscreen-Y
	 * @param image
	 *            The Image
	 */
	private void drawAddedRollingBallVoxels(int x, int y, ImagePlus image) {
		if (x > this.width || y > this.height) {
			return;
		}

		ImageProcessor tmpProc = image.getProcessor();

		tmpProc.setColor(Modell.MANUALLY_ADDED_VOXELS);
		tmpProc.setLineWidth(1);
		tmpProc.drawDot(x, y);
		
		this.manuallyAddedRollingBallVoxels.add(new Voxel(x, y, (image.getCurrentSlice() - 1), Modell.MANUALLY_ADDED_VOXELS.getRGB()));
		
		image.updateAndDraw();
	}
	
	/**
	 * Method that draws deleted Voxels on the Image
	 * 
	 * @param x
	 *            Offscreen-X
	 * @param y
	 *            Offscreen-Y
	 * @param image
	 *            The Image
	 */
	private void drawDeletedRollingBallVoxels(int x, int y, ImagePlus image) {

		if (x > this.width || y > this.height) {
			return;
		}

		ImageProcessor tmpProc = image.getProcessor();

		tmpProc.setColor(Modell.MANUALLY_DELETED_VOXELS);
		tmpProc.setLineWidth(1);
		tmpProc.drawDot(x, y);

		this.manuallyDeletedRollingBallVoxels.add(new Voxel(x, y, (image.getCurrentSlice() - 1), Modell.MANUALLY_DELETED_VOXELS.getRGB()));
		
		image.updateAndDraw();
	}
	
	/**
	 * Method that draws the added AV-Node Voxel
	 * 
	 * @param x
	 * @param y
	 * @param image
	 */
	private void drawAddedAVNode(int x, int y, ImagePlus image) {
		
		if (x > this.width || y > this.height) {
			return;
		}
		
		int z = image.getCurrentSlice()  ;
		
		ImageProcessor tmpProc = image.getProcessor();

		for (int i = -1 ; i <= 1 ; i++) {
			image.setSlice(z+i);
			tmpProc.setColor(Modell.AV_NODE_VOXELS);
			tmpProc.setLineWidth(3);
			tmpProc.drawDot(x, y);
		}
		
		image.setSlice(z);
		
		//index correction for 1D
		z -= 1;
		
		for ( int zz = -1 ; zz <= 1 ; zz++ )
			for (int yy = -1 ; yy <= 1 ; yy++) {
				for (int xx = -1 ; xx <= 1 ; xx++) {

				if ((x + xx) < 0 || (y + yy) < 0 || (x + xx) > this.width
						|| (y + yy) > this.height || ( z + zz  ) < 0 || (z + zz ) >= this.size ) {
					continue;
				}
				this.avNodeVoxels.add(new Voxel((x + xx), (y + yy), ( z + zz ), Modell.AV_NODE_VOXELS.getRGB()));
			}
		}
		image.updateAndDraw();
	}
	
	/**
	 * Method to reset the Segmentation
	 */
	private void resetSegmentation() {
		this.borderMarked = false;
		this.roiMarked = false;
		this.markBorder = false;
		this.markRoi = false;
		this.gui.markBorderButton.setSelection(false);
		this.gui.markROIButton.setSelection(false);

		if (this.canvas != null) {
			this.canvas.removeMouseListener(this);
			this.canvas.removeMouseMotionListener(this);
			this.canvas = null;
		}

		this.externalVoxels.clear();
		this.internalVoxels.clear();

		this.currentImage.setStack(this.currentImage.getTitle(),modell.getImageStack());

		Toolbar.getInstance().setTool(Toolbar.RECTANGLE);

		System.gc();
	}

	/**
	 * Calculate the Roi Parameters
	 * 
	 * @param image
	 */
	private void calcRoiParameters(ImagePlus image,boolean caSeg) {
		
		this.minRoiX = this.width;
		this.minRoiY = this.height;
		this.minRoiZ = this.size;
		this.maxRoiX = 0;
		this.maxRoiY = 0;
		this.maxRoiZ = 1;
		
		if (caSeg) {
			/*
			 * Get selected slices
			 */
			
			this.minRoiZ = Integer.parseInt(this.gui.fromSpinner.getText());
			this.maxRoiZ = Integer.parseInt(this.gui.toSpinner.getText());
			
			/*
			 * Get Minimum ROI
			 */
			
			for (Voxel v : this.externalVoxels) {
				
				if ( v.getX() < this.minRoiX ) {
					this.minRoiX = v.getX();
				}
				if ( v.getX() > this.maxRoiX ) {
					this.maxRoiX = v.getX();
				}
				if ( v.getY() < this.minRoiY ) {
					this.minRoiY = v.getY();
				}
				if ( v.getY() > this.maxRoiY ) {
					this.maxRoiY = v.getY();
				}
			}
			
			/*
			 * Add 15 Pixels "Safety Margin"
			 */
			
			this.minRoiX -= 15;
			if ( this.minRoiX < 0 ) {
				this.minRoiX = 0;
			}
			
			this.minRoiY -= 15;
			if ( this.maxRoiY < 0 ) {
				this.minRoiY = 0;
			}
			
			this.maxRoiX += 15;
			if ( this.maxRoiX > this.width ) {
				this.maxRoiX = this.width;
			}
			
			this.maxRoiY += 15;
			if ( this.maxRoiY > this.height ) {
				this.maxRoiY = this.height;
			}
			
		}
		
		this.modell.setRoiParameters(this.minRoiX, this.maxRoiX, this.minRoiY, this.maxRoiY, ( this.minRoiZ - 1 ), this.maxRoiZ);
	}
	
	/**
	 * Get steps factor for calculating the number of
	 * segmentation steps. <br><br>
	 * steps = (roi_area / steps_factor) + 25
	 * 
	 * @return
	 * 			step factor
	 */
	private int calcSegStepFactor() {
		
		switch (this.gui.performanceScale.getSelection() ) {
			case 1: return 200;
			case 2: return 175;
			case 3: return 150;
			case 4: return 125;
			case 5: return 100;
			default: return 0;
		}
	}

	
	/**
	 * Get the strength factor between the slices.
	 * 
	 * @return
	 * 			Strength factor
	 */
	private double calcSegStrengthFactor() {
		
		return ((double) this.gui.strengthScale.getSelection() / 100d );
	}
	
	/**
	 * Calculates the ROI-Parameters from the Overlay label Image
	 * 
	 * @param ip
	 */
	private void calcRoiFromOverlay(ImagePlus ip) {
		
		this.minRoiX = this.width;
		this.minRoiY = this.height;
		this.minRoiZ = this.size;
		this.maxRoiX = 0;
		this.maxRoiY = 0;
		this.maxRoiZ = 1;
		
		boolean firstSliceFound = false;
		boolean pixelFound = false;
		
		ImageStack iStack = ip.getStack();
		ImageProcessor iProc = ip.getProcessor();
		int[] pixel = null;
		
		for ( int z = 1 ; z < iStack.getSize() ; z++ ) {
			ip.setSlice(z);
			pixelFound = false;
			if (!firstSliceFound) {
				this.minRoiZ = z;
			}
			
			
			for ( int y = 0 ; y < iStack.getHeight() ; y++ ) {
				for ( int x = 0 ; x < iStack.getWidth() ; x++ ) {
					
					pixel = iProc.getPixel(x, y, pixel);
					
					if ( pixel[0] <= 3 && pixel[0] > 0 ) {
						pixelFound = true;
						firstSliceFound = true;
						if ( x < this.minRoiX ) {
							this.minRoiX = x;
						}
						if ( x > this.maxRoiX ) {
							this.maxRoiX = x;
						}
						if ( y < this.minRoiY ) {
							this.minRoiY = y;
						}
						if ( y > this.maxRoiY ) {
							this.maxRoiY = y;
						}
					}
					
				}
			}
			
			if ( !pixelFound && firstSliceFound ) {
				break;
			}
			this.maxRoiZ = z;
		}
		
		//Yet another safety margin
		
		this.minRoiX -= 15;
		if ( this.minRoiX < 0 ) {
			this.minRoiX = 0;
		}
		
		this.minRoiY -= 15;
		if ( this.maxRoiY < 0 ) {
			this.minRoiY = 0;
		}
		
		this.maxRoiX += 15;
		if ( this.maxRoiX > this.width ) {
			this.maxRoiX = this.width;
		}
		
		this.maxRoiY += 15;
		if ( this.maxRoiY > this.height ) {
			this.maxRoiY = this.height;
		}
		
		this.modell.setRoiParameters(this.minRoiX, this.maxRoiX, this.minRoiY, this.maxRoiY, ( this.minRoiZ - 1 ), this.maxRoiZ);
	}
	

	// ////////////////////////
	// //////Listeners/////////
	// ////////////////////////

	/*
	 * MouseMotionListender events
	 */
	@Override
	public void mouseDragged(MouseEvent e) {
		if (!this.afterASF && !this.drawAVNode && !this.afterRollingBallCorrection ) {
			if (this.canvas == null) {
				return;
			}
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);

			if (this.markBorder) {
				drawBorder(offscreenX, offscreenY, this.currentImage);
				//markBorder = true;
			} else if (this.markRoi) {
				drawRoi(offscreenX, offscreenY, this.currentImage);
				//markRoi = true;
			}
		} else if (this.afterASF && ! this.afterRollingBall && !this.drawAVNode && !this.afterRollingBallCorrection){
			if ( this.canvas == null ) {
				return;
			}
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);
			if (this.manuallyAddASFVoxels) {
				drawAddedASFVoxels(offscreenX, offscreenY, this.asfImage);
			} else if (this.manuallyDeleteASFVoxels) {
				drawDeletedASFVoxels(offscreenX, offscreenY, this.asfImage);
			}
		} else if ( this.afterRollingBallCorrection && !this.drawAVNode ){
			if (this.canvas == null ) {
				return;
			}
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);
			if (this.manuallyAddRollingBallVoxels && !this.drawAVNode) {
				drawAddedRollingBallVoxels(offscreenX, offscreenY, this.rollingBallImage);
			} else if (this.manuallyDeleteRollingBallVoxels) {
				drawDeletedRollingBallVoxels(offscreenX, offscreenY, this.rollingBallImage);
			}
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// Empty Block
	}
	
	

	// ////////////////////////////////////////////////////////

	/*
	 * MouseListener events
	 */
	@Override
	public void mouseClicked(MouseEvent e) {
		if (!this.afterASF && !this.drawAVNode && !this.afterRollingBallCorrection) {
			if (this.canvas == null) {
				return;
			}
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);

			if (this.markBorder) {
				drawBorder(offscreenX, offscreenY, this.currentImage);
				//markBorder = true;
			} else if (this.markRoi) {
				drawRoi(offscreenX, offscreenY, this.currentImage);
				//markRoi = true;
			}
		} else if (this.afterASF && !this.afterRollingBall && !this.drawAVNode && !this.afterRollingBallCorrection) {
			if ( this.canvas == null ) {
				return;
			}
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);
			if (this.manuallyAddASFVoxels) {
				drawAddedASFVoxels(offscreenX, offscreenY, this.asfImage);
			} else if (this.manuallyDeleteASFVoxels) {
				drawDeletedASFVoxels(offscreenX, offscreenY, this.asfImage);
			}
		} else if ( this.afterRollingBallCorrection && !this.drawAVNode) {
			if (this.canvas == null ) {
				return;
			}
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);
			if (this.manuallyAddRollingBallVoxels) {
				drawAddedRollingBallVoxels(offscreenX, offscreenY, this.rollingBallImage);
			} else if (this.manuallyDeleteRollingBallVoxels) {
				drawDeletedRollingBallVoxels(offscreenX, offscreenY, this.rollingBallImage);
			}
		}
		
		if ( this.drawAVNode ) {
			
			this.avNodeVoxels.clear();
			
			int x = e.getX();
			int y = e.getY();
			int offscreenX = this.canvas.offScreenX(x);
			int offscreenY = this.canvas.offScreenY(y);
			
			drawAddedAVNode(offscreenX, offscreenY, this.rollingBallImage);
			
			if (this.canvas != null) {
				this.canvas.removeMouseListener(this);
				this.canvas = null;
			}
			Toolbar.getInstance().setTool(Toolbar.RECTANGLE);
		}
	}

	public void mouseEntered(MouseEvent e) {
		// Empty Block
	}

	public void mouseExited(MouseEvent e) {
		// Empty Block
	}

	public void mousePressed(MouseEvent e) {
		// Empty Block
	}

	public void mouseReleased(MouseEvent e) {
		// Empty Block
	}

	// /////////////////////////////////////////////////

	/*
	 * SelectionListender Events
	 */

	@Override
	public void widgetSelected(SelectionEvent e) {

		// Actions that'll happen when the Border Button was Toggled
		if (e.getSource().equals(this.gui.markBorderButton)) {
			Button source = (Button) e.getSource();

			this.afterASF = false;
			// If the Button is toggled (pressed)
			if (source.getSelection()) {
				this.markBorder = true;
				this.markRoi = false;
				this.borderMarked = true;
				// this.roiMarked = false;
				this.gui.markROIButton.setSelection(false);

				Toolbar.getInstance().setTool(
						Toolbar.getInstance().getToolId("Pencil Tool"));

				this.canvas = this.currentImage.getCanvas();
				this.canvas.addMouseListener(this);
				this.canvas.addMouseMotionListener(this);

			} else {
				// Happenes when the Button was clicked again
				this.markBorder = false;
				if (this.canvas != null) {
					this.canvas.removeMouseListener(this);
					this.canvas.removeMouseMotionListener(this);
					this.canvas = null;
				}
				Toolbar.getInstance().setTool(Toolbar.RECTANGLE);
			}

		} else if (e.getSource().equals(this.gui.markROIButton)) {
			Button source = (Button) e.getSource();

			this.afterASF = false;
			// If the Button is toggled (pressed)
			if (source.getSelection()) {
				this.markRoi = true;
				this.markBorder = false;
				this.roiMarked = true;
				// this.borderMarked = false;
				this.gui.markBorderButton.setSelection(false);

				Toolbar.getInstance().setTool(
						Toolbar.getInstance().getToolId("Pencil Tool"));

				this.canvas = this.currentImage.getCanvas();
				this.canvas.addMouseListener(this);
				this.canvas.addMouseMotionListener(this);

			} else {
				this.markRoi = false;
				if (this.canvas != null) {
					this.canvas.removeMouseListener(this);
					this.canvas.removeMouseMotionListener(this);
					this.canvas = null;
				}
				Toolbar.getInstance().setTool(Toolbar.RECTANGLE);
			}

		} else if (e.getSource().equals(this.gui.selectSlicesButton)) {
			Button source = (Button) e.getSource();

			if (source.getSelection()) {
				this.gui.fromSpinner.setEnabled(true);
				this.gui.toSpinner.setEnabled(true);
			} else {
				this.gui.fromSpinner.setEnabled(false);
				this.gui.toSpinner.setEnabled(false);
			}
		} else if (e.getSource().equals(this.gui.strengthScale)) {
			Scale source = (Scale) e.getSource();
			this.gui.strengthLabel.setText("Strength between slices: "
					+ source.getSelection() + "%");

		} else if (e.getSource().equals(this.gui.resetButton)) {
			
			if ( this.ca3Dseg.isRunning() ) {
				return;
			}
			resetSegmentation();
			this.gui.segmentationButton.setEnabled(false);
			this.gui.asfStartButton.setEnabled(false);
			this.afterASF = false;
		} else if (e.getSource().equals(this.gui.segmentationButton)) {
			
//			if (this.ca3Dseg.isRunning()) {
//				return;
//			}

			if (this.roiMarked && this.borderMarked) {
				this.markBorder = false;
				this.markRoi = false;
				this.gui.markBorderButton.setSelection(false);
				this.gui.markROIButton.setSelection(false);
				if (this.canvas != null) {
					this.canvas.removeMouseListener(this);
					this.canvas.removeMouseMotionListener(this);
					this.canvas = null;
				}

				Toolbar.getInstance().setTool(Toolbar.RECTANGLE);

				this.ca3Dseg = CASegmentation3D.getInstance();

				if (this.ca3Dseg.isRunning()) {
					return;
				}
				
				calcRoiParameters(this.currentImage,true);

				/*
				 * Update parameter of ca3Dseg
				 */
				//TODO
				switch (this.gui.neighborhoodCombo.getSelectionIndex()) {
					case 0: this.ca3Dseg.setNeighborOption(CASegmentation3D.NEIGHBOR_MOORE); break;
					case 1: this.ca3Dseg.setNeighborOption(CASegmentation3D.NEIGHBOR_VON_NEUMANN); break;
				}
				
				switch (this.gui.maxGreyValueCombo.getSelectionIndex() ) {
					case 0: this.ca3Dseg.setGreyValueOption(CASegmentation3D.MAXGREYVALUE_GLOBAL); break;
					case 1: this.ca3Dseg.setGreyValueOption(CASegmentation3D.MAXGREYVALUE_LOCAL); break;
				}
				
				switch (this.gui.distanceCombo.getSelectionIndex()) {
					case 0: this.ca3Dseg.setDistanceOption(CASegmentation3D.DISTANCE_EUCLIDEAN); break;
					case 1: this.ca3Dseg.setDistanceOption(CASegmentation3D.DISTANCE_MANHATTAN); break;
				}
				
				this.modell.setInternalVoxels(Util.copyVoxelList(this.internalVoxels));
				this.modell.setExternalVoxels(Util.copyVoxelList(this.externalVoxels));
				this.ca3Dseg.setImageName(this.currentImage.getTitle());
				this.ca3Dseg.setGreyValue(this.volume);
				this.ca3Dseg.setSeqCounter(this.seqCounter);
				this.ca3Dseg.setStepsFactor(this.calcSegStepFactor());
				this.ca3Dseg.setStrengthFactor(this.calcSegStrengthFactor());
				this.ca3Dseg.setTmpSteps(0);//this.gui.stepScale.getSelection() * 5 );
				
				this.ca3Dseg.prepearCaSegmentation();
				
				this.afterASF = false;
				this.gui.asfStartButton.setEnabled(true);
			}
		} else if (e.getSource().equals(this.gui.saveButton)) {
			
			if ( this.ca3Dseg.isRunning()) {
				return;
			}
			String counter = "";
    		SaveDialog sDiag;
    		
    		/*
    		 * Create postfix number
    		 */
    		if(this.seqCounter <= 9){
    			counter = "00" + this.seqCounter;
    		}
    		else if(this.seqCounter > 9 && this.seqCounter <= 99){
    			counter = "0" + this.seqCounter;
    		}
    		else{
    			counter = "" + this.seqCounter;
    		}
    		
    		/*
    		 * Create save dialog
    		 */
    		sDiag = new SaveDialog("Save Segmentation Result...", this.currentImage.getTitle() + " - SegResult" + counter, ".tiff");
    		
    		/*
    		 * If save dialog is canceled .getFileName() returns null
    		 */
    		if(sDiag.getFileName() == null || sDiag.getDirectory() == null){
    			return;
    		}
    		else{
	    		String path = sDiag.getDirectory() + sDiag.getFileName();
	    		FileSaver fSaver = new FileSaver(this.ca3Dseg.createBinaryImageSequence());
	    		fSaver.saveAsTiffStack(path);
	    		
	    		this.seqCounter++;
    		}
		} else if (e.getSource().equals(this.gui.asfStartButton)) {
			
			this.morphFilter = AlternatingSequentialFilter.getInstance();
			
			if (this.morphFilter.isRunning() || this.ca3Dseg.isRunning()) {
				return;
			}
			
			this.morphFilter.setImageName(this.currentImage.getTitle());
			this.morphFilter.setStructureElements(Integer.valueOf(this.gui.asfSpinner.getText()));
			this.morphFilter.setOpenClose(this.gui.openCloseButton.getSelection());
			this.morphFilter.setSeqCounter(this.seqCounter);
			
			this.morphFilter.prepearAlternatingSequentialFilter();
			
			this.afterASF = true;
			this.gui.manualASFCorrectStartButton.setEnabled(true);
			this.gui.manualASFCorrectAddButton.setEnabled(true);
			this.gui.manualASFCorrectDeleteButton.setEnabled(true);
			this.gui.rollingBallStartButton.setEnabled(true); 
			
		} else if (e.getSource().equals(this.gui.rollingBallStartButton )) {
			this.rollingBall = RollingBallOperator.getInstance();
			
			if (this.rollingBall.isRunning()) {
				return;
			}
			
			//No morphological operations have performed
			this.rollingBall.setImageName(this.currentImage.getTitle());
			this.rollingBall.setLabelOneThickness(this.gui.avgColorOneSpinner.getSelection());
			this.rollingBall.setMinBloodMassOneThickness(this.gui.minColorOneSpinner.getSelection());
			this.rollingBall.setMaxBloodMassOneThickness(this.gui.maxColorOneSpinner.getSelection());
			
			this.rollingBall.setLabelTwoThickness(this.gui.avgColorTwoSpinner.getSelection());
			this.rollingBall.setMinBloodMassTwoThickness(this.gui.minColorTwoSpinner.getSelection());
			this.rollingBall.setMaxBloodMassTwoThickness(this.gui.maxColorTwoSpinner.getSelection());
			
			this.rollingBall.setSeqCounter(this.seqCounter);
			this.rollingBall.setMinGrayValue(Integer.parseInt( this.gui.minGrayValueText.getText().equals("") ? "0" : this.gui.minGrayValueText.getText()));
			this.rollingBall.setMaxGrayValue(Integer.parseInt( this.gui.maxGrayValueText.getText().equals("") ? "0" : this.gui.maxGrayValueText.getText()));
			
			this.rollingBall.prepearRollingBallOperator();
			this.gui.rollingBallSaveButton.setEnabled(true);
			
			this.gui.manualRollingBallCorrectAddButton.setEnabled(true);
			this.gui.manualRollingBallCorrectDeleteButton.setEnabled(true);
			this.gui.manualRollingBallCorrectStartButton.setEnabled(true);
			
			this.afterRollingBall = true;
			
		} else if (e.getSource().equals(this.gui.rollingBallSaveButton)) {
			
			if ( this.rollingBall.isRunning()) {
				return;
			}
			
			if ( useDialogs ) {
				String counter = "";
				SaveDialog sDiag;
    		
				/*
				 * Create postfix number
				 */
				if(this.seqCounter <= 9){
					counter = "00" + this.seqCounter;
				}
				else if(this.seqCounter > 9 && this.seqCounter <= 99){
					counter = "0" + this.seqCounter;
				}
				else{
					counter = "" + this.seqCounter;
				}
    		
				/*
				 * Create save dialog
				 */
				sDiag = new SaveDialog("Save RollingBall Result...", this.currentImage.getTitle() + " - RollingBallResult" + counter, ".tiff");
    		
				/*
				 * If save dialog is canceled .getFileName() returns null
				 */
				if(sDiag.getFileName() == null || sDiag.getDirectory() == null){
					return;
				}
				else{
					String path = sDiag.getDirectory() + sDiag.getFileName();
					FileSaver fSaver = new FileSaver(this.rollingBall.createImageSequence());
					fSaver.saveAsTiffStack(path);
	    		
					//	this.seqCounter++;
				}
			} else {
			
				FileSaver saver = new FileSaver(this.rollingBall.createImageSequence());
			
				saver.saveAsTiffStack(PATH);
			}
		} else if (e.getSource().equals(this.gui.manualASFCorrectAddButton)) {
			if ( this.morphFilter == null || this.morphFilter.isRunning() ) {
				return;
			}
			
			if ( !this.manuallyAddASFVoxels && !this.manuallyDeleteASFVoxels ) {
				this.asfImage = ij.WindowManager.getImage(this.morphFilter.getFullImageTitle());
			}
			
			this.manuallyAddASFVoxels = true;
			this.manuallyDeleteASFVoxels = false;
			
			if ( this.canvas == null ) {
				this.canvas = this.asfImage.getCanvas();
				this.canvas.addMouseListener(this);
				this.canvas.addMouseMotionListener(this);
			}
			
			Toolbar.getInstance().setTool(Toolbar.getInstance().getToolId("Pencil Tool"));
			
			
		} else if (e.getSource().equals(this.gui.manualASFCorrectDeleteButton)) {
			if ( this.morphFilter == null || this.morphFilter.isRunning() ) {
				return;
			}
			
			if ( !this.manuallyAddASFVoxels && !this.manuallyDeleteASFVoxels ) {
				this.asfImage = ij.WindowManager.getImage(this.morphFilter.getFullImageTitle());
			}
			
			this.manuallyAddASFVoxels = false;
			this.manuallyDeleteASFVoxels = true;
			
			if ( this.canvas == null ) {
				this.canvas = this.asfImage.getCanvas();
				this.canvas.addMouseListener(this);
				this.canvas.addMouseMotionListener(this);
			}
			
			Toolbar.getInstance().setTool(Toolbar.getInstance().getToolId("Pencil Tool"));
			
			
			
		} else if (e.getSource().equals(this.gui.manualASFCorrectStartButton)) {
			if ( this.morphFilter == null || this.morphFilter.isRunning() ) {
				return;
			}
			
			this.manualLabelingFilter = ManualCorrectionLabeling.getInstance();
			
			if ( this.canvas != null ) {
				this.canvas.removeMouseListener(this);
				this.canvas.removeMouseMotionListener(this);
				this.canvas = null;
			}
			
			Toolbar.getInstance().setTool(Toolbar.RECTANGLE);
			
			this.manualLabelingFilter.setManuallyAddedVoxels(Util.copyVoxelList(this.manuallyAddedASFVoxels));
			this.manualLabelingFilter.setManuallyDeletedVoxels(Util.copyVoxelList(this.manuallyDeletedASFVoxels));
			this.manualLabelingFilter.setFullImageTitle(this.morphFilter.getFullImageTitle());
			this.manualLabelingFilter.prepearManualCorrection();
			
			this.gui.manualASFCorrectAddButton.setSelection(false);
			this.gui.manualASFCorrectDeleteButton.setSelection(false);
			
			this.manuallyAddedASFVoxels.clear();
			this.manuallyDeletedASFVoxels.clear();
			
			this.manuallyAddASFVoxels = false;
			this.manuallyDeleteASFVoxels = false;
			
		} else if (e.getSource().equals(this.gui.manualRollingBallCorrectStartButton)) {
			
			if (this.rollingBall == null || this.rollingBall.isRunning() ){
				return;
			}
			
			this.manualCorrectRollingBall = ManualRollingBallCorrection.getInstance();
			
			if ( this.canvas != null ) {
				this.canvas.removeMouseListener(this);
				this.canvas.removeMouseMotionListener(this);
				this.canvas = null;
			}
			
			Toolbar.getInstance().setTool(Toolbar.RECTANGLE);
			
			this.manualCorrectRollingBall.setManuallyAddedRollingBallVoxels(Util.copyVoxelList(this.manuallyAddedRollingBallVoxels));
			this.manualCorrectRollingBall.setManuallyDeletedRollingBallVoxels(Util.copyVoxelList(this.manuallyDeletedRollingBallVoxels));
			
			this.manualCorrectRollingBall.setFullImageTitle(this.rollingBall.getFullImageTitle());
			this.manualCorrectRollingBall.prepearRollingBallCorrection();
			
			this.manuallyAddedRollingBallVoxels.clear();
			this.manuallyDeletedRollingBallVoxels.clear();
			
			this.gui.manualRollingBallCorrectAddButton.setSelection(false);
			this.gui.manualRollingBallCorrectDeleteButton.setSelection(false);
			
			this.manuallyAddRollingBallVoxels = false;
			this.manuallyDeleteRollingBallVoxels = false;
		} else if ( e.getSource().equals(this.gui.manualRollingBallCorrectAddButton)) {
			
			if ( this.rollingBall == null || this.rollingBall.isRunning() ) {
				return;
			}
			
			if ( !this.manuallyAddRollingBallVoxels && !this.manuallyDeleteASFVoxels) {
				this.rollingBallImage = ij.WindowManager.getImage(this.rollingBall.getFullImageTitle());
			}
			
			this.manuallyAddRollingBallVoxels = true;
			this.manuallyDeleteRollingBallVoxels = false;
			this.afterRollingBallCorrection = true;
			
			if ( this.canvas == null ) {
				this.canvas = this.rollingBallImage.getCanvas();
				this.canvas.addMouseListener(this);
				this.canvas.addMouseMotionListener(this);
			}
			
			Toolbar.getInstance().setTool(Toolbar.getInstance().getToolId("Pencil Tool"));
			
		} else if ( e.getSource().equals(this.gui.manualRollingBallCorrectDeleteButton)) {
			
			if ( this.rollingBall == null || this.rollingBall.isRunning() ) {
				return;
			}
			
			if ( !this.manuallyAddRollingBallVoxels && !this.manuallyDeleteRollingBallVoxels ) {
				this.rollingBallImage = ij.WindowManager.getImage(this.rollingBall.getFullImageTitle());
			}
			
			this.manuallyAddRollingBallVoxels = false;
			this.manuallyDeleteRollingBallVoxels = true;
			this.afterRollingBallCorrection = true;
			
			if ( this.canvas == null ) {
				this.canvas = this.rollingBallImage.getCanvas();
				this.canvas.addMouseListener(this);
				this.canvas.addMouseMotionListener(this);
			}
			
			Toolbar.getInstance().setTool(Toolbar.getInstance().getToolId("Pencil Tool"));
		} else if ( e.getSource().equals(this.gui.loadBinaryImageButton)) {
			
			ImagePlus overlayLabelImage = null;
			
			if ( useDialogs ) {
				OpenDialog openDlg;
			
				openDlg = new OpenDialog("Load Overlay", "");
			
				if ( openDlg.getDirectory() == null || openDlg.getFileName() == null ) {
					return;
				} else {
					String path = openDlg.getDirectory() + openDlg.getFileName();
					System.out.println(path);
					overlayLabelImage = new ImagePlus(path);
				}
			} else {
				overlayLabelImage = new ImagePlus(PATH);
			}
			
			this.loadedFromOverlay = true;
			
			calcRoiFromOverlay(overlayLabelImage);
			
			this.rollingBallImage = Util.loadOverlay(overlayLabelImage);
			
			this.rollingBallImage.setSlice(this.maxRoiZ);
			
			this.rollingBallImage.show();
			
			
		} else if (e.getSource().equals(this.gui.conductorDrawAVNodeButton)) {
			
			if (!loadedFromOverlay) { 
				this.rollingBallImage = ij.WindowManager.getImage(this.rollingBall.getFullImageTitle());
			}
			
			this.drawAVNode = true;
			this.manuallyAddRollingBallVoxels = false;
			this.manuallyDeleteRollingBallVoxels = false;
			
			this.manuallyAddASFVoxels = false;
			this.manuallyDeleteASFVoxels = false;
			this.afterRollingBallCorrection = false;
			
			if ( this.canvas == null ) {
				this.canvas = this.rollingBallImage.getCanvas();
				this.canvas.addMouseListener(this);
			}
			
			Toolbar.getInstance().setTool(Toolbar.getInstance().getToolId("Pencil Tool"));
			this.gui.conductorStartDrawing.setEnabled(true);
			
		} else if (e.getSource().equals((this.gui.conductorStartDrawing))) {
			
			this.conductorSystemCreator = ConductorSystemCreator.getInstance();
			
			if ( this.conductorSystemCreator.isRunning() ) {
				return;
			}
			
			this.modell.setAvNodeVoxels(Util.copyVoxelList(this.avNodeVoxels));
			
			this.conductorSystemCreator.setFullName(this.rollingBallImage.getTitle());
			
			
			this.conductorSystemCreator.prepearConductorCreation();
		}
			
		//Enable the Segmentation-Button 
		if ( borderMarked && roiMarked ) {
			this.gui.segmentationButton.setEnabled(true);
			
		}
	}


	public void widgetDefaultSelected(SelectionEvent e) {
		// Empty Block
	}

	// ///////////////////////////////////////////////////////////////////////

	/*
	 * ModifyListener Events
	 */

	@Override
	public void modifyText(ModifyEvent e) {

		if (e.getSource().equals(this.gui.pencilSizeSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			try {
				int value = Integer.parseInt(text);
				this.pencilSize = value;
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}

			}catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.pencilSizeSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.pencilSizeSpinner.getBounds();
				GC gc = new GC(this.gui.pencilSizeSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rect.x + pt.x + 15, rect.y + rect.height + 45 ));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.pencilSizeSpinner.setForeground(null);
			}
		} else if (e.getSource().equals(this.gui.fromSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			try {
				int value = Integer.parseInt(text);
				
				int toValue = Integer.parseInt(this.gui.toSpinner.getText());
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				if (value > toValue) {
					this.gui.toSpinner.setSelection(value);
				}
				this.currentImage.setSlice(value);

			}catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.fromSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.fromSpinner.getBounds();
				Rectangle compRect = this.gui.spinnerComp.getBounds();
				GC gc = new GC(this.gui.fromSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, compRect.x + rect.x + pt.x + 15, compRect.y + rect.y + rect.height + 45));
				
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.fromSpinner.setForeground(null);
			}
		} else if (e.getSource().equals(this.gui.toSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			try {
				int value = Integer.parseInt(text);
				int fromValue = Integer.parseInt(this.gui.fromSpinner.getText());
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
				if (value < fromValue) {
					this.gui.fromSpinner.setSelection(value);
				}
				this.currentImage.setSlice(value);

			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.toSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.toSpinner.getBounds();
				Rectangle compRect = this.gui.spinnerComp.getBounds();
				GC gc = new GC(this.gui.toSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, compRect.x + rect.x + pt.x + 15, compRect.y + rect.y + rect.height + 45));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.toSpinner.setForeground(null);
			}
		} else if (e.getSource().equals(this.gui.asfSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			try {
				int value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				if (value == 1) {
					this.gui.asfLabel.setText("3x3");
				} else {
					this.gui.asfLabel.setText("3x3 - " + (value*2 + 1) + "x" + (value*2 + 1));
				}

			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.asfSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.asfSpinner.getBounds();
				Rectangle compRect = this.gui.myocardiumGroup.getBounds();
				GC gc = new GC(this.gui.asfSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, compRect.x + rect.x + pt.x + 15, compRect.y + rect.y + rect.height + 25));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.asfSpinner.setForeground(null);
			}
		} else if (e.getSource().equals(this.gui.avgColorOneSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			try {
				int value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.avgColorOneSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.avgColorOneSpinner.getBounds();
				Rectangle rbrect = this.gui.rollingBallGroup.getBounds();
				Rectangle compRect = this.gui.rollingBallColorOneGroup.getBounds();
				GC gc = new GC(this.gui.avgColorOneSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbrect.x + compRect.x + rect.x + pt.x + 15, rbrect.y + compRect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.avgColorOneSpinner.setForeground(null);
			}
		} else if (e.getSource().equals(this.gui.minColorOneSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			int value = -1;
			try {
				value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.minColorOneSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.minColorOneSpinner.getBounds();
				Rectangle rbrect = this.gui.rollingBallGroup.getBounds();
				Rectangle compRect = this.gui.rollingBallColorOneGroup.getBounds();
				GC gc = new GC(this.gui.minColorOneSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbrect.x + compRect.x + rect.x + pt.x + 15, rbrect.y + compRect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.minColorOneSpinner.setForeground(null);
				this.gui.avgColorOneSpinner.setMinimum(value);
				this.gui.maxColorOneSpinner.setMinimum(value);
			}
		} else if (e.getSource().equals(this.gui.maxColorOneSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			int value = -1;
			try {
				value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.maxColorOneSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.maxColorOneSpinner.getBounds();
				Rectangle rbrect = this.gui.rollingBallGroup.getBounds();
				Rectangle compRect = this.gui.rollingBallColorOneGroup.getBounds();
				GC gc = new GC(this.gui.maxColorOneSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbrect.x + compRect.x + rect.x + pt.x + 15, rbrect.y + compRect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.maxColorOneSpinner.setForeground(null);
				this.gui.avgColorOneSpinner.setMaximum(value);
				this.gui.minColorOneSpinner.setMaximum(value);
				this.gui.rollingBallZSliceSpinner.setMaximum(this.gui.maxColorOneSpinner.getSelection() > this.gui.maxColorTwoSpinner.getSelection() ? this.gui.maxColorOneSpinner.getSelection() : this.gui.maxColorTwoSpinner.getSelection());
			}
		} else if (e.getSource().equals(this.gui.avgColorTwoSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			try {
				int value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.avgColorTwoSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.avgColorTwoSpinner.getBounds();
				Rectangle rbRect = this.gui.rollingBallGroup.getBounds();
				Rectangle compRect = this.gui.rollingBallColorTwoGroup.getBounds();
				GC gc = new GC(this.gui.avgColorTwoSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbRect.x + compRect.x + rect.x + pt.x + 15, rbRect.y + compRect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.avgColorTwoSpinner.setForeground(null);
			}
		} else if (e.getSource().equals(this.gui.minColorTwoSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			int value = -1;
			try {
				value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.minColorTwoSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.minColorTwoSpinner.getBounds();
				Rectangle rbrect = this.gui.rollingBallGroup.getBounds();
				Rectangle compRect = this.gui.rollingBallColorTwoGroup.getBounds();
				GC gc = new GC(this.gui.minColorTwoSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbrect.x + compRect.x + rect.x + pt.x + 15, rbrect.y + compRect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.minColorTwoSpinner.setForeground(null);
				this.gui.avgColorTwoSpinner.setMinimum(value);
				this.gui.maxColorTwoSpinner.setMinimum(value);
			}
		} else if (e.getSource().equals(this.gui.maxColorTwoSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			int value = -1;
			try {
				value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.maxColorTwoSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.maxColorTwoSpinner.getBounds();
				Rectangle rbrect = this.gui.rollingBallGroup.getBounds();
				Rectangle compRect = this.gui.rollingBallColorTwoGroup.getBounds();
				GC gc = new GC(this.gui.maxColorTwoSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbrect.x + compRect.x + rect.x + pt.x + 15, rbrect.y + compRect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.maxColorTwoSpinner.setForeground(null);
				this.gui.avgColorTwoSpinner.setMaximum(value);
				this.gui.minColorTwoSpinner.setMaximum(value);
				this.gui.rollingBallZSliceSpinner.setMaximum(this.gui.maxColorOneSpinner.getSelection() > this.gui.maxColorTwoSpinner.getSelection() ? this.gui.maxColorOneSpinner.getSelection() : this.gui.maxColorTwoSpinner.getSelection());
			}
		} else if (e.getSource().equals(this.gui.rollingBallZSliceSpinner)) {
			
			Spinner source = (Spinner) e.getSource();
			
			String text = source.getText();
			String message = null;
			int value = -1;
			try {
				value = Integer.parseInt(text);
				
				int maximum = source.getMaximum();
				int minimum = source.getMinimum();
				if (value > maximum) {
					message = "Current input is greater than the maximum limit ("+maximum+")";
				} else if (value < minimum) {
					message = "Current input is less than the minimum limit ("+minimum+")";
				}
				
			} catch (Exception ex) {
				message = "Current input is not numeric";
			}
			if (message != null ) {
				this.gui.rollingBallZSliceSpinner.setForeground(display.getSystemColor(SWT.COLOR_RED));
				Rectangle rect = this.gui.rollingBallZSliceSpinner.getBounds();
				Rectangle rbrect = this.gui.rollingBallGroup.getBounds();
				//Rectangle compRect = this.gui.rollingball.getBounds();
				GC gc = new GC(this.gui.rollingBallZSliceSpinner);
				Point pt = gc.textExtent(text);
				gc.dispose();
				this.gui.toolTip.setLocation(display.map(shell, null, rbrect.x + rect.x + pt.x + 15, rbrect.y + rect.y + rect.height + 39));
				this.gui.toolTip.setMessage(message);
				this.gui.toolTip.setVisible(true);
			} else {
				this.gui.toolTip.setVisible(false);
				this.gui.rollingBallZSliceSpinner.setForeground(null);
			}
		}
	}

	// ///////////////////////////////////////////////////////////////////////

	/*
	 * VerifyListener Events
	 */
	
	@Override
	public void verifyText(VerifyEvent e) {
		String string = e.text;
		char[] chars = new char[string.length()];
		string.getChars(0, chars.length, chars, 0);
		for ( int i = 0 ; i < chars.length ; i++ ) {
			if (! (chars[i] >= '0' && chars[i] <= '9' )) {
				e.doit = false;
				return;
			}
		}
	}
}